
package com.project.projectA.core.dao;

import java.util.Iterator;
import java.util.List;

import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.lang.StringUtils;

import com.google.common.collect.Lists;

/**
 * 提供分页对象.
 *
 * @param <T> the generic type
 * @author wuwei
 */
public class Page<T> implements Iterable<T> {
	//-- 公共变量 --//
	/** The Constant ASC. */
	public static final String ASC = "asc";

	/** The Constant DESC. */
	public static final String DESC = "desc";

	//-- 分页查询参数 --//
	/** The page no. */
	protected int pageNo = 1;

	/** The page size. */
	protected int pageSize = -1;

	/** The auto count. */
	protected boolean autoCount = true;

	/** The order by. */
	protected String orderBy = null;

	/** The order. */
	protected String order = null;

	//-- 返回结果 --//
	/** The result. */
	protected List<T> result = Lists.newArrayList();

	/** The total items. */
	protected long totalItems = -1;

	/** The all result. */
	protected boolean allResult = false;
	
	/** The all q result. */
	protected List<T> allQResult = Lists.newArrayList();
	
	/** The total count. */
	protected long totalCount = -1L;

	//-- 构造函数 --//
	/**
	 * Instantiates a new page.
	 */
	public Page() {
	}

	/**
	 * Instantiates a new page.
	 *
	 * @param pageSize the page size
	 */
	public Page(int pageSize) {
		setPageSize(pageSize);
	}

	/**
	 * Instantiates a new page.
	 *
	 * @param pageNo the page no
	 * @param pageSize the page size
	 */
	public Page(int pageNo, int pageSize) {
		setPageNo(pageNo);
		setPageSize(pageSize);
	}

	//-- 分页参数访问函数 --//
	/**
	 * 获得当前页的页号,序号从1开始,默认为1.
	 *
	 * @return the page no
	 */
	public int getPageNo() {
		return pageNo;
	}

	/**
	 * 设置当前页的页号,序号从1开始,低于1时自动调整为1.
	 *
	 * @param pageNo the new page no
	 */
	public void setPageNo(final int pageNo) {
		this.pageNo = pageNo;

		if (pageNo < 1) {
			this.pageNo = 1;
		}
	}

	/**
	 * 获得每页的记录数量, 默认为-1.
	 *
	 * @return the page size
	 */
	public int getPageSize() {
		return pageSize;
	}

	/**
	 * 设置每页的记录数量.
	 *
	 * @param pageSize the new page size
	 */
	public void setPageSize(final int pageSize) {
		this.pageSize = pageSize;
	}

	/**
	 * 获得排序字段,无默认值. 多个排序字段时用','分隔.
	 *
	 * @return the order by
	 */
	public String getOrderBy() {
		return orderBy;
	}

	/**
	 * 设置排序字段,多个排序字段时用','分隔.
	 *
	 * @param orderBy the new order by
	 */
	public void setOrderBy(final String orderBy) {
		this.orderBy = orderBy;
	}

	/**
	 * 获得排序方向, 无默认值.
	 *
	 * @return the order
	 */
	public String getOrder() {
		return order;
	}

	/**
	 * 设置排序方式向.
	 * 
	 * @param order 可选值为desc或asc,多个排序字段时用','分隔.
	 */
	public void setOrder(final String order) {
		String lowcaseOrder = StringUtils.lowerCase(order);

		//检查order字符串的合法值
		String[] orders = StringUtils.split(lowcaseOrder, ',');
		for (String orderStr : orders) {
			if (!StringUtils.equals(DESC, orderStr) && !StringUtils.equals(ASC, orderStr)) {
				throw new IllegalArgumentException("排序方向" + orderStr + "不是合法值");
			}
		}

		this.order = lowcaseOrder;
	}

	/**
	 * 是否已设置排序字段,无默认值.
	 *
	 * @return true, if is order by setted
	 */
	public boolean isOrderBySetted() {
		return (StringUtils.isNotBlank(orderBy) && StringUtils.isNotBlank(order));
	}

	/**
	 * 根据pageNo和pageSize计算当前页第一条记录在总结果集中的位置,序号从0开始.
	 * 用于Mysql,Hibernate.
	 *
	 * @return the offset
	 */
	public int getOffset() {
		return ((pageNo - 1) * pageSize);
	}

	/**
	 * 根据pageNo和pageSize计算当前页第一条记录在总结果集中的位置,序号从1开始.
	 * 用于Oracle.
	 *
	 * @return the start row
	 */
	public int getStartRow() {
		return getOffset() + 1;
	}

	/**
	 * 根据pageNo和pageSize计算当前页最后一条记录在总结果集中的位置, 序号从1开始.
	 * 用于Oracle.
	 *
	 * @return the end row
	 */
	public int getEndRow() {
		return pageSize * pageNo;
	}

	//-- 访问查询结果函数 --//

	/**
	 * 获得页内的记录列表.
	 *
	 * @return the result
	 */
	public List<T> getResult() {
		return result;
	}

	/**
	 * 设置页内的记录列表.
	 *
	 * @param result the new result
	 */
	public void setResult(final List<T> result) {
		this.result = result;
	}

	/**
	 * 实现Iterable接口,可以for(Object item : page)遍历使用.
	 *
	 * @return the iterator
	 */
	@SuppressWarnings("unchecked")
	public Iterator<T> iterator() {
		return result == null ? IteratorUtils.EMPTY_ITERATOR : result.iterator();
	}

	/**
	 * 获得总记录数, 默认值为-1.
	 *
	 * @return the total items
	 */
	public long getTotalItems() {
		return totalItems;
	}

	/**
	 * 设置总记录数.
	 *
	 * @param totalItems the new total items
	 */
	public void setTotalItems(final long totalItems) {
		this.totalItems = totalItems;
	}

	/**
	 * 是否最后一页.
	 *
	 * @return true, if is last page
	 */
	public boolean isLastPage() {
		return pageNo == getTotalPages();
	}

	/**
	 * 是否还有下一页.
	 *
	 * @return true, if is checks for next page
	 */
	public boolean isHasNextPage() {
		return (pageNo + 1 <= getTotalPages());
	}

	/**
	 * 取得下页的页号, 序号从1开始.
	 * 当前页为尾页时仍返回尾页序号.
	 *
	 * @return the next page
	 */
	public int getNextPage() {
		if (isHasNextPage()) {
			return pageNo + 1;
		} else {
			return pageNo;
		}
	}

	/**
	 * 是否第一页.
	 *
	 * @return true, if is first page
	 */
	public boolean isFirstPage() {
		return pageNo == 1;
	}

	/**
	 * 是否还有上一页.
	 *
	 * @return true, if is checks for pre page
	 */
	public boolean isHasPrePage() {
		return (pageNo - 1 >= 1);
	}

	/**
	 * 取得上页的页号, 序号从1开始.
	 * 当前页为首页时返回首页序号.
	 *
	 * @return the pre page
	 */
	public int getPrePage() {
		if (isHasPrePage()) {
			return pageNo - 1;
		} else {
			return pageNo;
		}
	}

	/**
	 * 根据pageSize与totalItems计算总页数, 默认值为-1.
	 *
	 * @return the total pages
	 */
	public long getTotalPagesTwo() {
		if (totalItems < 0) {
			return -1;
		}

		long count = totalItems / pageSize;
		if (totalItems % pageSize > 0) {
			count++;
		}
		return count;
	}

	 /**
 	 * Gets the total pages.
 	 *
 	 * @return the total pages
 	 */
 	public long getTotalPages()
  {
    if (this.totalCount < 0L) {
      return -1L;
    }

    long count = this.totalCount / this.pageSize;
    if (this.totalCount % this.pageSize > 0L) {
      count += 1L;
    }
    return count;
  }

	/**
	 * 计算以当前页为中心的页面列表,如"首页,23,24,25,26,27,末页".
	 *
	 * @param count 需要计算的列表大小
	 * @return pageNo列表
	 */
	public List<Long> getSlider(int count) {
		int halfSize = count / 2;
		long totalPage = getTotalPages();

		long startPageNumber = Math.max(pageNo - halfSize, 1);
		long endPageNumber = Math.min(startPageNumber + count - 1, totalPage);

		if (endPageNumber - startPageNumber < count) {
			startPageNumber = Math.max(endPageNumber - count, 1);
		}

		List<Long> r = Lists.newArrayList();
		for (long i = startPageNumber; i <= endPageNumber; i++) {
			r.add(new Long(i));
		}
		return r;
	}

	/**
	 * Gets the start record.
	 *
	 * @return the start record
	 */
	public int getStartRecord() {
		return (this.pageNo - 1) * this.pageSize + 1;
	}

	/**
	 * Gets the end record.
	 *
	 * @return the end record
	 */
	public int getEndRecord() {
		return Math.min(this.pageNo * this.pageSize, Long.valueOf(this.totalItems).intValue());
	}

	   /**
   	 * Gets the all q result.
   	 *
   	 * @return the all q result
   	 */
   	public List<T> getAllQResult() {
    return this.allQResult;
  }

  /**
   * Sets the all q result.
   *
   * @param allQResult the new all q result
   */
  public void setAllQResult(List<T> allQResult) {
    this.allQResult = allQResult;
  }

      /**
       * Checks if is all result.
       *
       * @return true, if is all result
       */
      public boolean isAllResult() {
    return this.allResult;
  }

  /**
   * Sets the all result.
   *
   * @param allResult the new all result
   */
  public void setAllResult(boolean allResult) {
    this.allResult = allResult;
  }

     /**
      * Gets the first.
      *
      * @return the first
      */
     public int getFirst()
  {
    return (this.pageNo - 1) * this.pageSize + 1;
  }

  /**
   * Gets the total count.
   *
   * @return the total count
   */
  public long getTotalCount()
  {
    return this.totalCount;
  }

  /**
   * Sets the total count.
   *
   * @param totalCount the new total count
   */
  public void setTotalCount(long totalCount)
  {
    this.totalCount = totalCount;
  }

    /**
     * Checks if is checks for next.
     *
     * @return true, if is checks for next
     */
    public boolean isHasNext()
  {
    return this.pageNo + 1 <= getTotalPages();
  }

   /**
    * Checks if is checks for pre.
    *
    * @return true, if is checks for pre
    */
   public boolean isHasPre()
  {
    return this.pageNo - 1 >= 1;
  }

   
}
